package main;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.border.Border;

import org.jdom.JDOMException;

import threads.FileSearcher;
import threads.SaveFolderSearcher;


public class GameDialog extends JDialog implements ActionListener, KeyListener,
	WindowListener{

	private static final long serialVersionUID = 1L;
	
	private final Interface context;
	private FileSearcher fileSearch;
	private SaveFolderSearcher saveSearch;
	
	private JTextField game;
	private JFileChooser chooser;
	private JButton add;
	private JRadioButton automatic;
	private JRadioButton manual;
	private JLabel path1;
	private JLabel path2;
	private final JTextArea files;
	private JScrollPane scroll;
	private JButton close;
	
	private AtomicBoolean doneAdding;

	public GameDialog(Frame fr, Interface context) {
		super(fr);
		this.context = context;
		this.setTitle("Add a game");
		this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		this.addWindowListener(this);
		this.setMinimumSize(new Dimension(300, 200));
		
		doneAdding = new AtomicBoolean(true);
		
		//forced in foreground
		this.setModal(true);
	    GridBagLayout gbl = new GridBagLayout();
	    this.setLayout(gbl);

		game = new JTextField();
		game.setPreferredSize(new Dimension(100, 30));
		game.addKeyListener(this);
	    addComponent( this, gbl, game, 
	    		GridBagConstraints.HORIZONTAL, 
	    		GridBagConstraints.CENTER,
	    		0, 0, 3, 2, 1.0, 0 );
	    
	    automatic = new JRadioButton("automatic");
		automatic.setPreferredSize(new Dimension(80, 15));
	    automatic.setSelected(true);
	    addComponent( this, gbl, automatic, 
	    		GridBagConstraints.NONE, 
	    		GridBagConstraints.SOUTHWEST,
	    		3, 0, 1, 1, 0, 0 );  
	    
	    manual = new JRadioButton("manual");
		manual.setPreferredSize(new Dimension(80, 15));
	    addComponent( this, gbl, manual, 
	    		GridBagConstraints.NONE, 
	    		GridBagConstraints.NORTHWEST,
	    		3, 1, 1, 1, 0, 0 );
	    
	    ButtonGroup g = new ButtonGroup();
	    g.add(automatic);
	    g.add(manual);
	    
	    add = new JButton("Add");
	    add.setActionCommand("add");
	    add.addActionListener(this);
	    addComponent( this, gbl, add, 
	    		GridBagConstraints.NONE, 
	    		GridBagConstraints.CENTER,
	    		4, 0, 1, 2, 0, 0 );
	    
	    path1 = new JLabel("Path: ");
	    path1.setFont(new Font(path1.getFont().getFontName(), Font.BOLD, path1.getFont().getSize()));
	    addComponent( this, gbl, path1, 
	    		GridBagConstraints.NONE, 
	    		GridBagConstraints.WEST,
	    		0, 2, 1, 1, 0, 0 );
	    
	    path2 = new JLabel("");
	    addComponent( this, gbl, path2, 
	    		GridBagConstraints.HORIZONTAL, 
	    		GridBagConstraints.WEST,
	    		1, 2, 4, 1, 1.0, 0 );
	    
	    files = new JTextArea();
	    files.setEditable(false);
	    files.setLayout(new GridLayout(0,1));
		Border blackline = BorderFactory.createLineBorder(Color.black);
		files.setBorder(blackline);
		
		scroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 
				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		scroll.getVerticalScrollBar().setUnitIncrement(16);
		scroll.getHorizontalScrollBar().setUnitIncrement(16);
		scroll.setViewportView(files);
	    addComponent( this, gbl, scroll, 
	    		GridBagConstraints.BOTH, 
	    		GridBagConstraints.CENTER,
	    		0, 3, 5, 1, 1.0, 1.0 );
	    
	    close = new JButton("Close >>>");
	    close.setActionCommand("close");
	    close.addActionListener(this);
	    addComponent( this, gbl, close, 
	    		GridBagConstraints.HORIZONTAL, 
	    		GridBagConstraints.CENTER,
	    		0, 4, 5, 1, 1.0, 0 );
	    
		chooser = new JFileChooser(System.getProperty("user.home"));
		chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		chooser.setAcceptAllFileFilterUsed(false);
		
		this.pack();
	}

	private void addComponent( Container cont,
			GridBagLayout gbl,
			Component c,
			int fill,
			int anchor,
			int x, int y,
			int width, int height,
			double weightx, double weighty ){
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.fill = fill;
		gbc.anchor = anchor;
		gbc.gridx = x; gbc.gridy = y;
		gbc.gridwidth = width; gbc.gridheight = height;
		gbc.weightx = weightx; gbc.weighty = weighty;
		gbl.setConstraints( c, gbc );
		cont.add( c );
	}
	
	public String removeSpaces(String input){
		if(input==null) return null;
		String output = "";
		//delete front spaces
		for(int i = 0; i<input.length(); i++){
			if(input.charAt(i)!=' '||(!(i+1==input.length())&&input.charAt(i+1)!=' '&&output.length()>0))
				output += input.charAt(i);
		}
		return output;
	}

	@Override
	public void actionPerformed(ActionEvent ev) {
		String command = ev.getActionCommand();
		if(command.equalsIgnoreCase("add")) {
			if(automatic.isSelected()){
				try {
					this.setCursor(Cursor
							.getPredefinedCursor(Cursor.WAIT_CURSOR));
					saveSearch = new SaveFolderSearcher(this, game.getText());
					saveSearch.start();
					add.setText("Manual");
					add.setActionCommand("manual");
					game.setEnabled(false);
					automatic.setEnabled(false);
					manual.setEnabled(false);
					return;
				} catch (JDOMException e) {
				} catch (IOException e) {}
			}
			this.showFileChooser(System.getProperty("user.home"));
		}else if(command.equalsIgnoreCase("cancel")){
			this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			if(fileSearch!=null) fileSearch.kill();
			this.doneAdding.set(true);
			this.clear();
		}else if(command.equalsIgnoreCase("manual")){
			this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			if(saveSearch!=null) saveSearch.kill();
			this.showFileChooser(System.getProperty("user.home"));
		}else if(command.equalsIgnoreCase("close")){
			this.windowClosing(null);
		}
	}
	
	public void reportFile(String path){
		files.append(path+"\n");
	}
	
	public synchronized void showFileChooser(String path){
		this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		if(saveSearch!=null) saveSearch.kill();
		if(!chooser.isShowing()){
			File f = new File(path);
			if(!f.isDirectory()) f = new File(System.getProperty("user.home"));
		
			chooser.setCurrentDirectory(f);
			chooser.setDialogTitle("Select Savefolder of " + game.getText());
			int success = chooser.showDialog(this, "Select");
			if (success == JFileChooser.APPROVE_OPTION) {
				String dirname = chooser.getSelectedFile().getAbsolutePath();
				File startdir = new File(dirname);
				if (startdir.exists()) {
					this.setCursor(Cursor
							.getPredefinedCursor(Cursor.WAIT_CURSOR));
					add.setText("Cancel");
					add.setActionCommand("cancel");
					game.setEnabled(false);
					path2.setText(dirname);
					automatic.setEnabled(false);
					manual.setEnabled(false);
					doneAdding.set(false);
					fileSearch = new FileSearcher(this, dirname);
					fileSearch.start();
				}
			}else{
				add.setText("Add");
				add.setActionCommand("add");
				game.setEnabled(true);
				path2.setText("");
				automatic.setEnabled(true);
				manual.setEnabled(true);
				doneAdding.set(true);
			}
		}
	}
	
	public void reportSaveFolderStatus(String caption, String message){
		this.path1.setText(caption+" ");
		this.path2.setText(message);
	}
	
	public void reportDone(List<GameFile> gamefiles, String dirname, long biggestTime){
		this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		add.setText("New");
		close.setVisible(true);
		close.requestFocus();
		doneAdding.set(true);
		context.addGame(removeSpaces(game.getText()), dirname, biggestTime, gamefiles);
	}
	
	public void clear() {
		this.setLocationRelativeTo(this.getParent());
		close.setVisible(false);
		add.setEnabled(false);
		add.setText("Add");
		add.setActionCommand("add");
		game.setEnabled(true);
		EventQueue.invokeLater(new Runnable(){
			@Override
			public void run() {
				files.setText("");
			}
		});
		path1.setText("Path: ");
		path2.setText("");	
		game.setText("");
		automatic.setEnabled(false);
		manual.setEnabled(false);
		game.requestFocus();
	}

	@Override
	public void keyPressed(KeyEvent e) {}

	@Override
	public void keyReleased(KeyEvent e) {
		if(e.getSource()==game){
			if(e.getKeyCode()==KeyEvent.VK_ENTER){
				if(!game.getText().equals("")) add.doClick();
				return;
			}
			if(game.getText().equals("")){
				add.setEnabled(false);
				automatic.setEnabled(false);
				manual.setEnabled(false);
			}else{
				add.setEnabled(true);
				automatic.setEnabled(true);
				manual.setEnabled(true);
			}
		}
	}

	@Override
	public void keyTyped(KeyEvent e) {}

	@Override
	public void windowActivated(WindowEvent e) {}

	@Override
	public void windowClosed(WindowEvent e) {}

	@Override
	public void windowClosing(WindowEvent e) {
		if(doneAdding.get()){
			context.enableBar();
			if(fileSearch!=null) fileSearch.kill();
			if(saveSearch!=null) saveSearch.kill();
			this.dispose();
		} else JOptionPane.showMessageDialog(this, 
				"Please wait for current operation to finish.", 
				"Warning", JOptionPane.WARNING_MESSAGE);
	}

	@Override
	public void windowDeactivated(WindowEvent e) {}

	@Override
	public void windowDeiconified(WindowEvent e) {}

	@Override
	public void windowIconified(WindowEvent e) {}

	@Override
	public void windowOpened(WindowEvent e) {}

}
